//
//  Confing.swift
//  CzzSwTest
//
//  Created by 陈钟 on 2018/9/21.
//  Copyright © 2018年 陈钟. All rights reserved.
//

import UIKit

public var DefaultgrayColor = UIColor.hexColor(hexStr: "#919191")
public var DefaultblackColor = UIColor.hexColor(hexStr: "#29303E")
public var DefaultborderColor = UIColor.hexColor(hexStr: "#D8D8D8")
public var DefaultBgColor = UIColor.hexColor(hexStr: "#F3F3F3")

/// 颜色
public func RGB(r:CGFloat,g:CGFloat,b:CGFloat,a:CGFloat = 1) -> UIColor {
    return UIColor.init(red: r / 255, green: g / 255, blue: b / 255, alpha: a)
}

public typealias CreateLabelAlisa = (_ label:UILabel) -> ()
public func createLabel(block:CreateLabelAlisa?) -> UILabel {
    let label = UILabel.init()
    if block != nil{
        block?(label)
    }
    return label
}

@available(iOS 8.2, *)
public func FontSize(size:CGFloat, weight: UIFont.Weight) -> UIFont{
    return UIFont.systemFont(ofSize: size, weight: weight)
}

//@available(iOS, introduced: 6.0, deprecated: 8.2)
public func FontSize(size:CGFloat) -> UIFont{
    return UIFont.systemFont(ofSize: size)
}

public func FontBoldSize(size:CGFloat) -> UIFont {
    if #available(iOS 8.2, *) {
        return FontSize(size: size, weight: .bold)
    } else {
        return UIFont.boldSystemFont(ofSize: size)
    }
}

/// UUID
public var uuidString: String{
    return UIDevice.current.identifierForVendor?.uuidString ?? ""
}

/// Keywindow
public var keyWindow: UIWindow? {
    if #available(iOS 13.0, *) {
        guard let scene = UIApplication.shared.connectedScenes.first,
              let sceneDelegate = scene.delegate as? UIWindowSceneDelegate,
              let window = sceneDelegate.window else {
            let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
            return window
        }
        return window
    } else {
        return UIApplication.shared.keyWindow
    }
}

/// 用户手机别名
public var PhoneName: String {
    return UIDevice.current.name
}

/// 设备名称
public var SystemName: String {
    return UIDevice.current.systemName
}

/// 设备系统版本
public var SystemVersion: String {
    return UIDevice.current.systemVersion
}

/// APP版本
public var appVersion: String {
    let appversion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
    return appversion ?? ""
}

/// APP Build
public var appBuild: String {
    let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String
    return build ?? ""
}

/// APP名字
public var appName: String {
    let appname = Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String
    guard let name = appname else {
        let newname = Bundle.main.infoDictionary?["CFBundleName"] as? String
        return newname ?? ""
    }
    return name
}

/// 是否是iPhone X
public var isIPhoneX: Bool {
    var isIPhoneX : Bool = false
    if #available(iOS 11.0, *) {
//        isIPhoneX = UIApplication.shared.delegate?.window??.safeAreaInsets.bottom ?? 0 > 0
        isIPhoneX = (keyWindow?.safeAreaInsets.bottom ?? 0) > 0
    }
    return isIPhoneX;
}

public var isGlass: Bool {
    if #available(iOS 26, *) {
        if let isGlass = Bundle.main.infoDictionary?["UIDesignRequiresCompatibility"] as? Bool{
            return !isGlass
        }
        return true
    } else {
        return false;
    }
}

/// 是否是 iphone5 及以下
public var isIphone5OrLess: Bool {
    return (isIphone && screen_max_length <= 568.0)
}

/// 是否是iPad
public var isIpad: Bool {
    return UIDevice.current.userInterfaceIdiom == .pad
}

/// 是否是iPhone
public var isIphone: Bool {
    return UIDevice.current.userInterfaceIdiom == .phone
}

/// 是否是暗黑模式
public var isDarkModel: Bool{
    if #available(iOS 13, *) {
        return UITraitCollection.current.userInterfaceStyle == .dark
    } else {
        return false
    }
}

/// 是否是Retina
public var isRetina: Bool {
    return UIScreen.main.scale >= 2
}

/// 屏幕宽度
public var screen_width: CGFloat {
    return UIScreen.main.bounds.size.width
}

/// 屏幕高度
public var screen_height: CGFloat {
    return UIScreen.main.bounds.size.height
}

/// 屏幕最大边
public var screen_max_length: CGFloat {
    return max(screen_width, screen_height)
}

/// 屏幕最小边
public var screen_min_length: CGFloat {
    return min(screen_width, screen_height)
}

/// 最小边的比例
public var screen_min_scale: CGFloat {
    return screen_min_length / CGFloat.init(375)
}

/// 状态栏高度
public var statusBarHeight: CGFloat {
    return keyWindow?.safeAreaInsets.top ?? 0
}

/// navigationBar 高度
public let navigationBarHeight: CGFloat = statusBarHeight + (isGlass ? 54 : 44)

/// iphonex 下方多出高度
public var safeAreaHeight: CGFloat {
    return keyWindow?.safeAreaInsets.bottom ?? 0
}

/// TabBar 高度
public let tabBarHeight: CGFloat = 49.0 + safeAreaHeight


//MARK: - 文件路径

/// bundle
public func file_bundle(name: String,type: String) -> String? {
    return Bundle.main.path(forResource: name, ofType: type)
}

/// documents
public func file_documents() -> String {
    return NSHomeDirectory() + "/Documents"
}

/// documents filename
public func file_documents(filename: String) -> String {
    let file_path = NSHomeDirectory() + "/Documents/" + filename
    return file_path
}

/// 将字符串转换成URL
public func Url(url string:String?) -> URL? {
    if let url = string{
        return URL.init(string: url)
    }
    return nil
}
/// 字符串转 文件路径URL
public func Url(file string:String?) -> URL? {
    if let fileUrl = string{
        return URL.init(fileURLWithPath: fileUrl)
    }
    return nil
}

//MARK: - LOG
public func ZZLog<T>(_ message:T,file:String = #file,funcName:String = #function,lineNum:Int = #line) {
    #if DEBUG
    // 设置在DEBUG 环境下打印LOG ， DEBUG就是在Build Settings 里面设置的标识。
    // 1.获取打印所在的文件
    let file = (file as NSString).lastPathComponent
//    //2.获取打印所在的方法
//    let funcName = funcName
    //3.获取打印所在的行
    let lineNum = lineNum
//    print("\(file) (\(lineNum)) \(funcName) : \(message)")
    print("\(file) (\(lineNum)): \(message)")
    #endif
}

@objcMembers public class ZZTool: NSObject {
    //MARK: - 非空判断
    /// 判断字符串是否为空
    public static func isNull(text:String?) -> Bool {
        if text == nil { return true }
        if text!.count <= 0 { return true }
        return false
    }
    //MARK: - 公用方法
    /// 跳转App Store 评论界面
    public static func jumpToAppStoreComments(appid:String) -> Void {
        var urlStr = "itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=\(appid)"
        if #available(iOS 11.0, *) {
            urlStr = "itms-apps://itunes.apple.com/us/app/id\(appid)?mt=8&action=write-review"
        }
        guard let url = Url(url: urlStr) else { return }
        if #available(iOS 10.0, *) {
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
        } else {
            // Fallback on earlier versions
            UIApplication.shared.openURL(url)
        }
    }

    /// 通过Safari 打开网址
    /// - Parameter urlStr: 网址 
    public static func openURL(_ urlStr: String?){
        guard let url = Url(url: urlStr) else { return }
        if #available(iOS 10.0, *) {
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
        } else {
            // Fallback on earlier versions
            UIApplication.shared.openURL(url)
        }
    }

    /// 拨打电话
    ///
    /// - Parameter phone: 电话号码
    public static func call(_ phone:String) -> Void {
        if let phoneUrl:URL = URL.init(string: "tel:\(phone)") {
            if #available(iOS 10.0, *) {
                UIApplication.shared.open(phoneUrl, options: [:], completionHandler: nil)
            } else {
                UIApplication.shared.openURL(phoneUrl)
            }
        }
    }

    /// 时间字符串转换成时间戳
    public static func timeStamp(_ timerStr: String?,formart: String) -> TimeInterval{
        guard let dateStr = timerStr else { return 0 }
        let date = self.getDate(dateString: dateStr, formatter: formart)
        return self.timeStampToMS(date: date)
    }

    /// 时间转时间戳 精确到毫秒
    public static func timeStampToMS(date:Date) -> TimeInterval {
        let timeInterval: TimeInterval = date.timeIntervalSince1970
        let millisecond = CLongLong(round(timeInterval * 1000))
//        return "\(millisecond)"
        return TimeInterval(millisecond)
    }

    /// 时间转时间戳
    public static func timeStamp(date:Date) -> TimeInterval {
        let timeInterval: TimeInterval = date.timeIntervalSince1970
        let timeStamp = Int(timeInterval)
//        return "\(timeStamp)"
        return TimeInterval(timeStamp)
    }

    /// 将时间戳转换成格式事件
    /// - Parameters:
    ///   - timeStamp: 时间戳
    ///   - formatter: 转换格式
    public static func dateString(for timeStamp:TimeInterval, formatter:String) -> String{
        let date = self.getDate(timeStamp: timeStamp)
        return self.dateString(date: date, formatter: formatter)
    }

    /// 时间戳转换成时间
    public static func getDate(timeStamp:TimeInterval) -> Date {
        return Date.init(timeIntervalSince1970: timeStamp)
    }

    ///将时间转成 星期
    public static func dateToWeek(date:Date,title:String?) -> String {
        let calender = Calendar.init(identifier: .gregorian)
        let comps = calender.component(.weekday, from: date)
        var weekStr : String = "一"
        switch comps {
            case 1:do{ weekStr = "日"  }
            case 2:do{ weekStr = "一"  }
            case 3:do{ weekStr = "二"  }
            case 4:do{ weekStr = "三"  }
            case 5:do{ weekStr = "四"  }
            case 6:do{ weekStr = "五"  }
            case 7:do{ weekStr = "六"  }
            default: do{}
        }
        return String.init(format: "%@%@", title ?? "",weekStr)
    }

    /// 比较两个时间前后
    public static func compareDate(oneDate:Date,anotherDate:Date,formatter:String?) -> ComparisonResult {
        let dateFormatter = DateFormatter.init()
        dateFormatter.dateFormat = (formatter == nil) ? "" : formatter!

        let oneDayStr = dateFormatter.string(from: oneDate)
        let anotherDayStr = dateFormatter.string(from: anotherDate)

        let dateOne = dateFormatter.date(from: oneDayStr)!
        let dateAnother = dateFormatter.date(from: anotherDayStr)!

        let result = dateOne.compare(dateAnother)

        return result
    }


    /// 获取一个时间偏移天时间  负数过去时间 整数未来时间
    public static func getDate(date:Date,offsetDay:Int) -> Date {
        let calender = Calendar.current
        var lastComps = DateComponents.init()
        lastComps.day = offsetDay
        let newdate = calender.date(byAdding: lastComps, to: date)
        return newdate!
    }

    /// 获取一个时间偏移小时时间  负数过去时间 整数未来时间
    public static func getDate(date:Date,offsetHour:Int) -> Date {
        let calender = Calendar.current
        var lastComps = DateComponents.init()
        lastComps.hour = offsetHour
        let newdate = calender.date(byAdding: lastComps, to: date)
        return newdate!
    }

    /// 将时间字符串转换成时间
    public static func getDate(dateString:String,formatter:String) -> Date{
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = formatter
        return dateFormatter.date(from: dateString)!
    }

    /// 将时间字符串转换成新的的时间字符串
    /// - Parameters:
    ///   - dateStr: 时间字符串
    ///   - dateFormatter: 原本时间字符串formart
    ///   - toDateFormatter: 将要转换成的formart
    /// - Returns: 新的时间字符串
    public static func dateString(date dateStr: String?,fromFormatter dateFormatter: String,toFormatter toDateFormatter: String) -> String?{
        guard let dateString = dateStr, dateString.count > 0 else { return nil }
        let date = self.getDate(dateString: dateString, formatter: dateFormatter)
        let newDateString = self.dateString(date: date, formatter: toDateFormatter)
        return newDateString
    }

    /// 将时间转换成字符串
    public static func dateString(date:Date,formatter:String) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = formatter
        return dateFormatter.string(from: date)
    }
    /// 计算一个时间戳间隔当前时间 自动计算是当前时间前后
    public static func distanceTime(timeInterval:Int) -> String {
        if timeInterval <= 0 { return "" }
        let beTimeInterval: TimeInterval = Double(timeInterval) / 1000.0

        let nowDate = Date()
        let nowTimeInterval = nowDate.timeIntervalSince1970

        var distanceTime = nowTimeInterval - beTimeInterval

        if distanceTime > 0 {
            return distanceTimeBefore(timeInterval: timeInterval)
        }

        var distanceStr = ""
        distanceTime = fabs(distanceTime)

        if distanceTime < 60 {
            distanceStr = "现在"
        }else if (distanceTime < (60 * 60)){
            distanceStr = "\(Int(distanceTime / 60.0))分钟后"
        }else if (distanceTime < (60 * 60 * 24)){
            let distanceHour = distanceTime / 60 / 60
            let distanceMinute = (Int(distanceTime) % (60 * 60)) / 60
            distanceStr = "\(Int(distanceHour))小时\(Int(distanceMinute))分后"
        }else if (distanceTime < (60 * 60 * 24 * 30)){
            let distanceDay = distanceTime / 60 / 60 / 24;
            let distanceHour = (Int(distanceTime) % (60 * 60 * 24)) / 60 / 60
            let distanceMinute = (Int(distanceTime) % (60 * 60 * 24) % (60 * 60)) / 60
            distanceStr = "\(Int(distanceDay))天\(Int(distanceHour))小时\(Int(distanceMinute))分后"
        }else if (distanceTime < (60 * 60 * 24 * 365)){
            let distanceMonth = distanceTime / 60 / 60 / 24 / 30;
            distanceStr = String.init(format: "%.1f月后", distanceMonth)
        }else{
            let distanceYear = distanceTime / 60 / 60 / 24 / 30 / 365;
            distanceStr = String.init(format: "%.1f年后", distanceYear)
        }
        return distanceStr
    }

    /// 计算一个时间戳在当前时间前多少
    ///
    /// - Parameter timeInterval: 精确到 毫秒
    /// - Returns:
    public static func distanceTimeBefore(timeInterval:Int) -> String {
        if timeInterval <= 0 { return "" }

        let beTimeInterval: TimeInterval = Double(timeInterval) / 1000.0

        let nowDate = Date()
        let nowTimeInterval = nowDate.timeIntervalSince1970

        let distanceTime = nowTimeInterval - beTimeInterval

        var distanceStr = ""

        let beDate = Date.init(timeIntervalSince1970: beTimeInterval)

        let formart = DateFormatter.init()

        let calendar = Calendar.current
        let unitFlags = Calendar.Component.year


        let beComponents = calendar.dateComponents([unitFlags], from: beDate)
        let nowComponents = calendar.dateComponents([unitFlags], from: nowDate)

        let beYear = beComponents.year
        let nowYear = nowComponents.year

        formart.dateFormat = "HH:mm"
        let timeStr = formart.string(from: beDate)

        formart.dateFormat = "dd"
        let nowDay = formart.string(from: nowDate)
        let lastDay = formart.string(from: beDate)

        if distanceTime < 1 {
            distanceStr = "刚刚"
        }else if distanceTime < 60 {
            distanceStr = "\(Int(distanceTime))秒前"
        }else if (distanceTime < (60 * 60)){
            distanceStr = "\(Int(distanceTime / 60.0))分钟前"
        }else if (distanceTime < (60 * 60 * 24) && Int(nowDay) == Int(lastDay)){
            distanceStr = "\(Int(distanceTime / 60.0 / 60.0))小时前"
        }else if (distanceTime < (60 * 60 * 24 * 2) && Int(nowDay) != Int(lastDay)){
            if ((Int(nowDay) ?? 0) - (Int(lastDay) ?? 0)) == 1 ||
                ((Int(lastDay) ?? 0) - (Int(nowDay) ?? 0)) > 10 &&
                (Int(nowDay) ?? 0) == 1
            {
                distanceStr = "昨天 \(timeStr)"
            }else{
                formart.dateFormat = "MM月dd日 HH:mm"
                distanceStr = formart.string(from: beDate)
            }
        }else if (distanceTime < (60 * 60 * 24 * 365) && beYear == nowYear){
            formart.dateFormat = "MM月dd日 HH:mm"
            distanceStr = formart.string(from: beDate)
        }else{
            formart.dateFormat = "yyyy年MM月dd日 HH:mm"
            distanceStr = formart.string(from: beDate)
        }

        return distanceStr
    }

    /// 判断是否是小数
    public static func isPurnInt(string: String) -> Bool {
        let scan : Scanner = Scanner(string: string)
        var val : Float = 0
        if #available(iOS 13.0, *) {
            return scan.scanHexFloat(&val) && scan.isAtEnd
        } else {
            return scan.scanFloat(&val) && scan.isAtEnd
        }
    }

    /// 计算是否是整数
    public static func isIntNumber(string: String) -> Bool {
        let flotvalue = Double(string)
        let intvalue = Int(flotvalue ?? 0)
        if Double(intvalue) == flotvalue {
            return true
        }
        return false
    }


    /// 计算文字的Size
    ///
    /// - Parameters:
    ///   - text: 文字
    ///   - font: 字体
    ///   - size: 最大大小
    /// - Returns: 文字Size
    public static func textSize(_ text:String,font:UIFont,size:CGSize) -> CGSize {
        if text.count == 0 { return CGSize.zero }

        let textStr : NSString = text as NSString

        var textSize = CGSize.zero
        if size == CGSize.zero {
            let stringStyle = NSMutableDictionary.init()
            stringStyle.setObject(font, forKey: kCTFontAttributeName as! NSCopying)
            textSize = textStr.size(withAttributes: stringStyle as? [NSAttributedString.Key : Any])
        }else{
            let stringStyle = NSMutableDictionary.init()
            stringStyle.setObject(font, forKey: kCTFontAttributeName as! NSCopying)
            let rect = textStr.boundingRect(with: size, options: [.usesLineFragmentOrigin,.usesFontLeading,.truncatesLastVisibleLine], attributes: stringStyle as? [NSAttributedString.Key : Any], context: nil)
            textSize = rect.size
        }
        textSize = CGSize.init(width: CGFloat(ceilf(Float(textSize.width))), height: CGFloat(ceilf(Float(textSize.height))))//用进一发取整
        return textSize
    }

    /// 根据NSAttributedString计算文字的Size
    ///
    /// - Parameters:
    ///   - attString: NSAttributedString
    ///   - size: 指定大小
    /// - Returns: 文字大小
    public static func textSize(_ attString:NSAttributedString,font: UIFont? = nil,size:CGSize, numLine: Int = 0) -> CGSize {
        let label = UILabel.init(frame: CGRect.init(origin: CGPoint.zero, size: size))
        label.numberOfLines = numLine
        if font != nil {
            label.font = font
        }
        label.attributedText = attString
        label.sizeToFit()
        var frame = label.frame
        if frame.zz_width > size.width{
            frame.zz_width = size.width
        }
        return frame.size
    }

    /// 计算文字size  lineheight
    /// - Parameters:
    ///   - text: 文字
    ///   - font: 字体
    ///   - size: 计算框量
    ///   - lineHeight: 行高
    public static func textSize(_ text: String, font: UIFont? = nil, size: CGSize, lineHeight: CGFloat, numLine: Int = 0) -> CGSize{
        let pla = NSMutableParagraphStyle()
        pla.lineSpacing = lineHeight
        let titleAtt = NSMutableAttributedString(string: text)
        titleAtt.addAttribute(NSAttributedString.Key.paragraphStyle, value: pla, range: NSRange(location: 0, length: text.count))
        return self.textSize(titleAtt, font: font, size: size, numLine: numLine)

    }

    /// 对象转json字符串
    /// - Parameter json: json对象
    public static func jsonString(_ json: Any?) -> String?{
        if json == nil { return nil }
        guard let data = try? JSONSerialization.data(withJSONObject: json!, options: []) else { return nil }
        let jsonString = String(data: data, encoding: String.Encoding.utf8)
        return jsonString
    }

    /// 字符串转字典或者数组
    /// - Parameters:
    ///   - jsonString: json字符串
    public static func jsonValue(form jsonString: String?) -> Any?{
        guard let json = jsonString else { return nil }
        guard let data = json.data(using: .utf8) else { return nil }
        let value = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers)
        return value
    }

    /// 将Codable data转成model
    /// - Parameters:
    ///   - type: 模型类型
    ///   - json: json data
    public static func jsonDecode<T>(_ type: T.Type, json: Data?) -> T? where T : Decodable{
        if json == nil { return nil }
        do {
            let obj = try JSONDecoder().decode(type, from: json!)
            return obj
        }catch{
            return nil
        }
    }

    /// 将Codable 字典转成model
    /// - Parameters:
    ///   - type: 模型类型
    ///   - json: json data
    public static func jsonDecode<T>(_ type: T.Type, json: Any?) -> T? where T : Decodable{
        var jsonObj = json
        if json is String {
            jsonObj = ZZTool.jsonValue(form:json as? String)
        }
        if jsonObj == nil { return nil }

        let data = try? JSONSerialization.data(withJSONObject: jsonObj!, options: [])
        return self.jsonDecode(type, json: data)
    }

    /// 将Codable 模型转换成json字符串
    /// - Parameter model: 模型
    public static func modelEncoder<T>(_ model: T?) -> String? where T : Encodable{
        if model == nil { return nil }
        do {
            let data = try JSONEncoder().encode(model)
            let json = String(data: data, encoding: .utf8)
            return json
        }catch{
            return nil
        }
    }


}

public extension  NSObject{
    
    @objc var object: Any? {
        set {
            let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "object".hashValue)
            objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        
        get {
            let key : UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "object".hashValue)
            let obj = objc_getAssociatedObject(self, key)
            return obj
        }
    }
    
    @objc var anotherObject: Any? {
        set {
            let key: UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "anotherObject".hashValue)
            objc_setAssociatedObject(self, key, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        
        get {
            let key : UnsafeRawPointer! = UnsafeRawPointer.init(bitPattern: "anotherObject".hashValue)
            let obj = objc_getAssociatedObject(self, key)
            return obj
        }
    }
}

